From b7743430aa1471c9ec054606d2234700e2da3eda Mon Sep 17 00:00:00 2001 From: Mike Gorse Date: Sun, 11 Nov 2012 11:00:49 -0600 Subject: [PATCH] Add accessibles for GtkEntry icons Expose GtkEntry icons as child accessibles of a GtkEntry, and provide actions to simulate clicking them. Also, refactor the a11y children test slightly to add a test. https://bugzilla.gnome.org/show_bug.cgi?id=686347 --- gtk/a11y/gtkentryaccessible.c | 527 ++++++++++++++++++++++++++++++++++ tests/a11y/children.c | 101 +++++-- tests/a11y/entries.txt | 58 +++- tests/a11y/entries.ui | 8 + 4 files changed, 676 insertions(+), 18 deletions(-) diff --git a/gtk/a11y/gtkentryaccessible.c b/gtk/a11y/gtkentryaccessible.c index bac2b02b52..5f113da7e9 100644 --- a/gtk/a11y/gtkentryaccessible.c +++ b/gtk/a11y/gtkentryaccessible.c @@ -17,18 +17,351 @@ #include "config.h" +#include #include #include "gtkpango.h" #include "gtkentryaccessible.h" #include "gtkentryprivate.h" #include "gtkcomboboxaccessible.h" +#define GTK_TYPE_ENTRY_ICON_ACCESSIBLE (_gtk_entry_icon_accessible_get_type ()) +#define GTK_ENTRY_ICON_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_ENTRY_ICON_ACCESSIBLE, GtkEntryIconAccessible)) +#define GTK_IS_ENTRY_ICON_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_ENTRY_ICON_ACCESSIBLE)) + struct _GtkEntryAccessiblePrivate { gint cursor_position; gint selection_bound; + AtkObject *icons[2]; }; +typedef struct _GtkEntryIconAccessible GtkEntryIconAccessible; +typedef struct _GtkEntryIconAccessibleClass GtkEntryIconAccessibleClass; + +struct _GtkEntryIconAccessible +{ + AtkObject parent; + + GtkEntryAccessible *entry; + GtkEntryIconPosition pos; +}; + +struct _GtkEntryIconAccessibleClass +{ + AtkObjectClass parent_class; +}; + +static void atk_action_interface_init (AtkActionIface *iface); + +static void icon_atk_action_interface_init (AtkActionIface *iface); +static void icon_atk_component_interface_init (AtkComponentIface *iface); + +GType _gtk_entry_icon_accessible_get_type (void); + +G_DEFINE_TYPE_WITH_CODE (GtkEntryIconAccessible, _gtk_entry_icon_accessible, ATK_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (ATK_TYPE_ACTION, icon_atk_action_interface_init) + G_IMPLEMENT_INTERFACE (ATK_TYPE_COMPONENT, icon_atk_component_interface_init)) + +static void +gtk_entry_icon_accessible_remove_entry (gpointer data, GObject *obj) +{ + GtkEntryIconAccessible *icon = data; + + if (icon->entry) + { + icon->entry = NULL; + g_object_notify (G_OBJECT (icon), "accessible-parent"); + atk_object_notify_state_change (ATK_OBJECT (icon), ATK_STATE_DEFUNCT, TRUE); + } +} + +static AtkObject * +gtk_entry_icon_accessible_new (GtkEntryAccessible *entry, + GtkEntryIconPosition pos) +{ + GtkEntryIconAccessible *icon; + AtkObject *accessible; + + icon = g_object_new (_gtk_entry_icon_accessible_get_type (), NULL); + icon->entry = entry; + g_object_weak_ref (G_OBJECT (entry), + gtk_entry_icon_accessible_remove_entry, + icon); + icon->pos = pos; + + accessible = ATK_OBJECT (icon); + atk_object_initialize (accessible, NULL); + return accessible; +} + +static void +_gtk_entry_icon_accessible_init (GtkEntryIconAccessible *icon) +{ +} + +static void +gtk_entry_icon_accessible_initialize (AtkObject *obj, + gpointer data) +{ + GtkEntryIconAccessible *icon = GTK_ENTRY_ICON_ACCESSIBLE (obj); + GtkWidget *widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (icon->entry)); + GtkEntry *gtk_entry = GTK_ENTRY (widget); + const gchar *name; + gchar *text; + + ATK_OBJECT_CLASS (_gtk_entry_icon_accessible_parent_class)->initialize (obj, data); + atk_object_set_role (obj, ATK_ROLE_ICON); + + name = gtk_entry_get_icon_name (gtk_entry, icon->pos); + if (name) + atk_object_set_name (obj, name); + + text = gtk_entry_get_icon_tooltip_text (gtk_entry, icon->pos); + if (text) + { + atk_object_set_description (obj, text); + g_free (text); + } + + atk_object_set_parent (obj, ATK_OBJECT (icon->entry)); +} + +static AtkObject * +gtk_entry_icon_accessible_get_parent (AtkObject *accessible) +{ + GtkEntryIconAccessible *icon = GTK_ENTRY_ICON_ACCESSIBLE (accessible); + + return ATK_OBJECT (icon->entry); +} + +static AtkStateSet * +gtk_entry_icon_accessible_ref_state_set (AtkObject *accessible) +{ + GtkEntryIconAccessible *icon = GTK_ENTRY_ICON_ACCESSIBLE (accessible); + AtkStateSet *set = atk_state_set_new (); + AtkStateSet *entry_set; + GtkWidget *widget; + GtkEntry *gtk_entry; + + if (!icon->entry) + { + atk_state_set_add_state (set, ATK_STATE_DEFUNCT); + return set; + } + + entry_set = atk_object_ref_state_set (ATK_OBJECT (icon->entry)); + if (!entry_set || atk_state_set_contains_state (entry_set, ATK_STATE_DEFUNCT)) + { + atk_state_set_add_state (set, ATK_STATE_DEFUNCT); + g_clear_object (&entry_set); + return set; + } + + widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (icon->entry)); + gtk_entry = GTK_ENTRY (widget); + + if (atk_state_set_contains_state (entry_set, ATK_STATE_ENABLED)) + atk_state_set_add_state (set, ATK_STATE_ENABLED); + if (atk_state_set_contains_state (entry_set, ATK_STATE_SENSITIVE)) + atk_state_set_add_state (set, ATK_STATE_SENSITIVE); + if (atk_state_set_contains_state (entry_set, ATK_STATE_SHOWING)) + atk_state_set_add_state (set, ATK_STATE_SHOWING); + if (atk_state_set_contains_state (entry_set, ATK_STATE_VISIBLE)) + atk_state_set_add_state (set, ATK_STATE_VISIBLE); + + if (!gtk_entry_get_icon_sensitive (gtk_entry, icon->pos)) + atk_state_set_remove_state (set, ATK_STATE_SENSITIVE); + if (!gtk_entry_get_icon_activatable (gtk_entry, icon->pos)) + atk_state_set_remove_state (set, ATK_STATE_ENABLED); + + g_object_unref (entry_set); + return set; +} + +static void +gtk_entry_icon_accessible_invalidate (GtkEntryIconAccessible *icon) +{ + if (!icon->entry) + return; + g_object_weak_unref (G_OBJECT (icon->entry), + gtk_entry_icon_accessible_remove_entry, + icon); + gtk_entry_icon_accessible_remove_entry (icon, NULL); +} + +static void +gtk_entry_icon_accessible_finalize (GObject *object) +{ + GtkEntryIconAccessible *icon = GTK_ENTRY_ICON_ACCESSIBLE (object); + + gtk_entry_icon_accessible_invalidate (icon); + + G_OBJECT_CLASS (_gtk_entry_icon_accessible_parent_class)->finalize (object); +} + +static void +_gtk_entry_icon_accessible_class_init (GtkEntryIconAccessibleClass *klass) +{ + AtkObjectClass *atk_class = ATK_OBJECT_CLASS (klass); + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + atk_class->initialize = gtk_entry_icon_accessible_initialize; + atk_class->get_parent = gtk_entry_icon_accessible_get_parent; + atk_class->ref_state_set = gtk_entry_icon_accessible_ref_state_set; + + gobject_class->finalize = gtk_entry_icon_accessible_finalize; +} + +static gboolean +gtk_entry_icon_accessible_do_action (AtkAction *action, + gint i) +{ + GtkEntryIconAccessible *icon = (GtkEntryIconAccessible *)action; + GtkWidget *widget; + GtkEntry *gtk_entry; + GdkEvent event; + GdkRectangle icon_area; + + widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (icon->entry)); + if (widget == NULL) + return FALSE; + + if (i != 0) + return FALSE; + + if (!gtk_widget_is_sensitive (widget) || !gtk_widget_get_visible (widget)) + return FALSE; + + gtk_entry = GTK_ENTRY (widget); + + if (!gtk_entry_get_icon_sensitive (gtk_entry, icon->pos) || + !gtk_entry_get_icon_activatable (gtk_entry, icon->pos)) + return FALSE; + + gtk_entry_get_icon_area (gtk_entry, icon->pos, &icon_area); + memset (&event, 0, sizeof (event)); + event.button.type = GDK_BUTTON_PRESS; + event.button.window = gtk_widget_get_window (widget); + event.button.button = 1; + event.button.send_event = TRUE; + event.button.time = GDK_CURRENT_TIME; + event.button.x = icon_area.x; + event.button.y = icon_area.y; + + g_signal_emit_by_name (widget, "icon-press", 0, icon->pos, &event); + return TRUE; +} + +static gint +gtk_entry_icon_accessible_get_n_actions (AtkAction *action) +{ + GtkEntryIconAccessible *icon = GTK_ENTRY_ICON_ACCESSIBLE (action); + GtkWidget *widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (icon->entry)); + GtkEntry *gtk_entry = GTK_ENTRY (widget); + + return (gtk_entry_get_icon_activatable (gtk_entry, icon->pos) ? 1 : 0); +} + +static const gchar * +gtk_entry_icon_accessible_get_name (AtkAction *action, + gint i) +{ + GtkEntryIconAccessible *icon = GTK_ENTRY_ICON_ACCESSIBLE (action); + GtkWidget *widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (icon->entry)); + GtkEntry *gtk_entry = GTK_ENTRY (widget); + + if (i != 0) + return NULL; + if (!gtk_entry_get_icon_activatable (gtk_entry, icon->pos)) + return NULL; + + return "activate"; +} + +static void +icon_atk_action_interface_init (AtkActionIface *iface) +{ + iface->do_action = gtk_entry_icon_accessible_do_action; + iface->get_n_actions = gtk_entry_icon_accessible_get_n_actions; + iface->get_name = gtk_entry_icon_accessible_get_name; +} + +static void +gtk_entry_icon_accessible_get_extents (AtkComponent *component, + gint *x, + gint *y, + gint *width, + gint *height, + AtkCoordType coord_type) +{ + GtkEntryIconAccessible *icon = GTK_ENTRY_ICON_ACCESSIBLE (component); + GdkRectangle icon_area; + GtkEntry *gtk_entry; + GtkWidget *widget; + + *x = G_MININT; + atk_component_get_extents (ATK_COMPONENT (icon->entry), x, y, width, height, + coord_type); + if (*x == G_MININT) + return; + + widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (icon->entry)); + gtk_entry = GTK_ENTRY (widget); + gtk_entry_get_icon_area (gtk_entry, icon->pos, &icon_area); + *width = icon_area.width; + *height = icon_area.height; + *x += icon_area.x; + *y += icon_area.y; +} + +static void +gtk_entry_icon_accessible_get_position (AtkComponent *component, + gint *x, + gint *y, + AtkCoordType coord_type) +{ + GtkEntryIconAccessible *icon = GTK_ENTRY_ICON_ACCESSIBLE (component); + GdkRectangle icon_area; + GtkEntry *gtk_entry; + GtkWidget *widget; + + *x = G_MININT; + atk_component_get_position (ATK_COMPONENT (icon->entry), x, y, coord_type); + if (*x == G_MININT) + return; + + widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (icon->entry)); + gtk_entry = GTK_ENTRY (widget); + gtk_entry_get_icon_area (gtk_entry, icon->pos, &icon_area); + *x += icon_area.x; + *y += icon_area.y; +} + +static void +gtk_entry_icon_accessible_get_size (AtkComponent *component, + gint *width, + gint *height) +{ + GtkEntryIconAccessible *icon = GTK_ENTRY_ICON_ACCESSIBLE (component); + GdkRectangle icon_area; + GtkEntry *gtk_entry; + GtkWidget *widget; + + widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (icon->entry)); + gtk_entry = GTK_ENTRY (widget); + gtk_entry_get_icon_area (gtk_entry, icon->pos, &icon_area); + *width = icon_area.width; + *height = icon_area.height; +} + +static void +icon_atk_component_interface_init (AtkComponentIface *iface) +{ + iface->get_extents = gtk_entry_icon_accessible_get_extents; + iface->get_size = gtk_entry_icon_accessible_get_size; + iface->get_position = gtk_entry_icon_accessible_get_position; +} + /* Callbacks */ static void insert_text_cb (GtkEditable *editable, @@ -137,11 +470,13 @@ gtk_entry_accessible_notify_gtk (GObject *obj, AtkObject* atk_obj; GtkEntry* gtk_entry; GtkEntryAccessible* entry; + GtkEntryAccessiblePrivate *priv; widget = GTK_WIDGET (obj); atk_obj = gtk_widget_get_accessible (widget); gtk_entry = GTK_ENTRY (widget); entry = GTK_ENTRY_ACCESSIBLE (atk_obj); + priv = entry->priv; if (g_strcmp0 (pspec->name, "cursor-position") == 0) { @@ -174,6 +509,119 @@ gtk_entry_accessible_notify_gtk (GObject *obj, new_role = visibility ? ATK_ROLE_TEXT : ATK_ROLE_PASSWORD_TEXT; atk_object_set_role (atk_obj, new_role); } + else if (g_strcmp0 (pspec->name, "primary-icon-storage-type") == 0) + { + if (gtk_entry_get_icon_storage_type (gtk_entry, GTK_ENTRY_ICON_PRIMARY) != GTK_IMAGE_EMPTY && !priv->icons[GTK_ENTRY_ICON_PRIMARY]) + { + priv->icons[GTK_ENTRY_ICON_PRIMARY] = gtk_entry_icon_accessible_new (entry, GTK_ENTRY_ICON_PRIMARY); + g_signal_emit_by_name (entry, "children-changed::add", 0, + priv->icons[GTK_ENTRY_ICON_PRIMARY], NULL); + } + else if (gtk_entry_get_icon_storage_type (gtk_entry, GTK_ENTRY_ICON_PRIMARY) == GTK_IMAGE_EMPTY && priv->icons[GTK_ENTRY_ICON_PRIMARY]) + { + gtk_entry_icon_accessible_invalidate (GTK_ENTRY_ICON_ACCESSIBLE (priv->icons[GTK_ENTRY_ICON_PRIMARY])); + g_signal_emit_by_name (entry, "children-changed::remove", 0, + priv->icons[GTK_ENTRY_ICON_PRIMARY], NULL); + g_clear_object (&priv->icons[GTK_ENTRY_ICON_PRIMARY]); + } + } + else if (g_strcmp0 (pspec->name, "secondary-icon-storage-type") == 0) + { + gint index = (priv->icons[GTK_ENTRY_ICON_PRIMARY] ? 1 : 0); + if (gtk_entry_get_icon_storage_type (gtk_entry, GTK_ENTRY_ICON_SECONDARY) != GTK_IMAGE_EMPTY && !priv->icons[GTK_ENTRY_ICON_SECONDARY]) + { + priv->icons[GTK_ENTRY_ICON_SECONDARY] = gtk_entry_icon_accessible_new (entry, GTK_ENTRY_ICON_SECONDARY); + g_signal_emit_by_name (entry, "children-changed::add", index, + priv->icons[GTK_ENTRY_ICON_SECONDARY], NULL); + } + else if (gtk_entry_get_icon_storage_type (gtk_entry, GTK_ENTRY_ICON_SECONDARY) == GTK_IMAGE_EMPTY && priv->icons[GTK_ENTRY_ICON_SECONDARY]) + { + gtk_entry_icon_accessible_invalidate (GTK_ENTRY_ICON_ACCESSIBLE (priv->icons[GTK_ENTRY_ICON_SECONDARY])); + g_signal_emit_by_name (entry, "children-changed::remove", index, + priv->icons[GTK_ENTRY_ICON_SECONDARY], NULL); + g_clear_object (&priv->icons[GTK_ENTRY_ICON_SECONDARY]); + } + } + else if (g_strcmp0 (pspec->name, "primary-icon-name") == 0) + { + if (priv->icons[GTK_ENTRY_ICON_PRIMARY]) + { + const gchar *name; + name = gtk_entry_get_icon_name (gtk_entry, + GTK_ENTRY_ICON_PRIMARY); + atk_object_set_name (priv->icons[GTK_ENTRY_ICON_PRIMARY], name); + } + } + else if (g_strcmp0 (pspec->name, "secondary-icon-name") == 0) + { + if (priv->icons[GTK_ENTRY_ICON_SECONDARY]) + { + const gchar *name; + name = gtk_entry_get_icon_name (gtk_entry, + GTK_ENTRY_ICON_SECONDARY); + atk_object_set_name (priv->icons[GTK_ENTRY_ICON_SECONDARY], name); + } + } + else if (g_strcmp0 (pspec->name, "primary-icon-tooltip-text") == 0) + { + if (priv->icons[GTK_ENTRY_ICON_PRIMARY]) + { + gchar *text; + text = gtk_entry_get_icon_tooltip_text (gtk_entry, + GTK_ENTRY_ICON_PRIMARY); + atk_object_set_description (priv->icons[GTK_ENTRY_ICON_PRIMARY], + text); + g_free (text); + } + } + else if (g_strcmp0 (pspec->name, "secondary-icon-tooltip-text") == 0) + { + if (priv->icons[GTK_ENTRY_ICON_SECONDARY]) + { + gchar *text; + text = gtk_entry_get_icon_tooltip_text (gtk_entry, + GTK_ENTRY_ICON_SECONDARY); + atk_object_set_description (priv->icons[GTK_ENTRY_ICON_SECONDARY], + text); + g_free (text); + } + } + else if (g_strcmp0 (pspec->name, "primary-icon-activatable") == 0) + { + if (priv->icons[GTK_ENTRY_ICON_PRIMARY]) + { + gboolean on = gtk_entry_get_icon_activatable (gtk_entry, GTK_ENTRY_ICON_PRIMARY); + atk_object_notify_state_change (priv->icons[GTK_ENTRY_ICON_PRIMARY], + ATK_STATE_ENABLED, on); + } + } + else if (g_strcmp0 (pspec->name, "secondary-icon-activatable") == 0) + { + if (priv->icons[GTK_ENTRY_ICON_SECONDARY]) + { + gboolean on = gtk_entry_get_icon_activatable (gtk_entry, GTK_ENTRY_ICON_SECONDARY); + atk_object_notify_state_change (priv->icons[GTK_ENTRY_ICON_SECONDARY], + ATK_STATE_ENABLED, on); + } + } + else if (g_strcmp0 (pspec->name, "primary-icon-sensitive") == 0) + { + if (priv->icons[GTK_ENTRY_ICON_PRIMARY]) + { + gboolean on = gtk_entry_get_icon_sensitive (gtk_entry, GTK_ENTRY_ICON_PRIMARY); + atk_object_notify_state_change (priv->icons[GTK_ENTRY_ICON_PRIMARY], + ATK_STATE_SENSITIVE, on); + } + } + else if (g_strcmp0 (pspec->name, "secondary-icon-sensitive") == 0) + { + if (priv->icons[GTK_ENTRY_ICON_SECONDARY]) + { + gboolean on = gtk_entry_get_icon_sensitive (gtk_entry, GTK_ENTRY_ICON_SECONDARY); + atk_object_notify_state_change (priv->icons[GTK_ENTRY_ICON_SECONDARY], + ATK_STATE_SENSITIVE, on); + } + } else GTK_WIDGET_ACCESSIBLE_CLASS (_gtk_entry_accessible_parent_class)->notify_gtk (obj, pspec); } @@ -192,19 +640,98 @@ gtk_entry_accessible_get_index_in_parent (AtkObject *accessible) return ATK_OBJECT_CLASS (_gtk_entry_accessible_parent_class)->get_index_in_parent (accessible); } +static gint +gtk_entry_accessible_get_n_children (AtkObject* obj) +{ + GtkWidget *widget; + GtkEntry *entry; + gint count = 0; + + widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (obj)); + if (widget == NULL) + return 0; + + entry = GTK_ENTRY (widget); + + if (gtk_entry_get_icon_storage_type (entry, GTK_ENTRY_ICON_PRIMARY) != GTK_IMAGE_EMPTY) + count++; + if (gtk_entry_get_icon_storage_type (entry, GTK_ENTRY_ICON_SECONDARY) != GTK_IMAGE_EMPTY) + count++; + return count; +} + +static AtkObject * +gtk_entry_accessible_ref_child (AtkObject *obj, + gint i) +{ + GtkEntryAccessible *accessible = GTK_ENTRY_ACCESSIBLE (obj); + GtkEntryAccessiblePrivate *priv = accessible->priv; + GtkWidget *widget; + GtkEntry *entry; + GtkEntryIconPosition pos; + + widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (obj)); + if (widget == NULL) + return NULL; + + entry = GTK_ENTRY (widget); + + switch (i) + { + case 0: + if (gtk_entry_get_icon_storage_type (entry, GTK_ENTRY_ICON_PRIMARY) != GTK_IMAGE_EMPTY) + pos = GTK_ENTRY_ICON_PRIMARY; + else if (gtk_entry_get_icon_storage_type (entry, GTK_ENTRY_ICON_SECONDARY) != GTK_IMAGE_EMPTY) + pos = GTK_ENTRY_ICON_SECONDARY; + else + return NULL; + break; + case 1: + if (gtk_entry_get_icon_storage_type (entry, GTK_ENTRY_ICON_PRIMARY) == GTK_IMAGE_EMPTY) + return NULL; + if (gtk_entry_get_icon_storage_type (entry, GTK_ENTRY_ICON_SECONDARY) == GTK_IMAGE_EMPTY) + return NULL; + pos = GTK_ENTRY_ICON_SECONDARY; + break; + default: + return NULL; + } + + if (!priv->icons[pos]) + priv->icons[pos] = gtk_entry_icon_accessible_new (accessible, pos); + return g_object_ref (priv->icons[pos]); +} + +static void +gtk_entry_accessible_finalize (GObject *object) +{ + GtkEntryAccessible *entry = GTK_ENTRY_ACCESSIBLE (object); + GtkEntryAccessiblePrivate *priv = entry->priv; + + g_clear_object (&priv->icons[GTK_ENTRY_ICON_PRIMARY]); + g_clear_object (&priv->icons[GTK_ENTRY_ICON_SECONDARY]); + + G_OBJECT_CLASS (_gtk_entry_accessible_parent_class)->finalize (object); +} + static void _gtk_entry_accessible_class_init (GtkEntryAccessibleClass *klass) { AtkObjectClass *class = ATK_OBJECT_CLASS (klass); GtkWidgetAccessibleClass *widget_class = (GtkWidgetAccessibleClass*)klass; + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); class->ref_state_set = gtk_entry_accessible_ref_state_set; class->get_index_in_parent = gtk_entry_accessible_get_index_in_parent; class->initialize = gtk_entry_accessible_initialize; class->get_attributes = gtk_entry_accessible_get_attributes; + class->get_n_children = gtk_entry_accessible_get_n_children; + class->ref_child = gtk_entry_accessible_ref_child; widget_class->notify_gtk = gtk_entry_accessible_notify_gtk; + gobject_class->finalize = gtk_entry_accessible_finalize; + g_type_class_add_private (klass, sizeof (GtkEntryAccessiblePrivate)); } diff --git a/tests/a11y/children.c b/tests/a11y/children.c index 19b1e607d8..dfd289484f 100644 --- a/tests/a11y/children.c +++ b/tests/a11y/children.c @@ -23,6 +23,12 @@ #include #include +typedef struct +{ + GtkWidget *widget; + gpointer child[3]; +} STATE; + static void test_scrolled_window_child_count (void) { @@ -70,16 +76,38 @@ add_child (GtkWidget *container, } static void -remove_child (GtkWidget *container, - GtkWidget *child) +remove_child (STATE *state, + gint i) { - if (GTK_IS_SCROLLED_WINDOW (container)) + GtkWidget *child; + + if (GTK_IS_ENTRY (state->widget)) + { + switch (i) + { + case 0: + gtk_entry_set_icon_from_gicon (GTK_ENTRY (state->widget), + GTK_ENTRY_ICON_PRIMARY, + NULL); + return; + case 1: + gtk_entry_set_icon_from_gicon (GTK_ENTRY (state->widget), + GTK_ENTRY_ICON_SECONDARY, + NULL); + return; + default: + return; + } + } + + child = state->child [i]; + if (GTK_IS_SCROLLED_WINDOW (state->widget)) { - if (gtk_widget_get_parent (child) != container) + if (gtk_widget_get_parent (child) != state->widget) child = gtk_widget_get_parent (child); } - gtk_container_remove (GTK_CONTAINER (container), child); + gtk_container_remove (GTK_CONTAINER (state->widget), child); } static void @@ -89,6 +117,34 @@ parent_notify (AtkObject *obj, GParamSpec *pspec, SignalData *data) data->parent = atk_object_get_parent (obj); } +gboolean +do_create_child (STATE *state, gint i) +{ + if (GTK_IS_ENTRY (state->widget)) + { + switch (i) + { + case 0: + gtk_entry_set_icon_from_stock (GTK_ENTRY (state->widget), + GTK_ENTRY_ICON_PRIMARY, + GTK_STOCK_CAPS_LOCK_WARNING); + return TRUE; + case 1: + gtk_entry_set_icon_from_stock (GTK_ENTRY (state->widget), + GTK_ENTRY_ICON_SECONDARY, + GTK_STOCK_CLEAR); + return TRUE; + default: + return FALSE; + } + } + else if (gtk_container_child_type (GTK_CONTAINER (state->widget)) == G_TYPE_NONE) + return FALSE; + + state->child[i] = gtk_label_new ("bla"); + return TRUE; +} + static void test_add_remove (GtkWidget *widget) { @@ -97,10 +153,11 @@ test_add_remove (GtkWidget *widget) SignalData add_data; SignalData remove_data; SignalData parent_data[3]; - GtkWidget *child[3]; + STATE state; gint i, j; gint step_children; + state.widget = widget; accessible = gtk_widget_get_accessible (widget); add_data.count = 0; @@ -114,35 +171,44 @@ test_add_remove (GtkWidget *widget) for (i = 0; i < 3; i++) { - if (gtk_container_child_type (GTK_CONTAINER (widget)) == G_TYPE_NONE) + if (!do_create_child (&state, i)) break; - - child[i] = gtk_label_new ("bla"); - parent_data[i].count = 0; - child_accessible = gtk_widget_get_accessible (child[i]); - g_signal_connect (child_accessible, "notify::accessible-parent", - G_CALLBACK (parent_notify), &(parent_data[i])); - add_child (widget, child[i]); + if (!GTK_IS_ENTRY (widget)) + { + parent_data[i].count = 0; + child_accessible = gtk_widget_get_accessible (state.child[i]); + g_signal_connect (child_accessible, "notify::accessible-parent", + G_CALLBACK (parent_notify), &(parent_data[i])); + add_child (widget, state.child[i]); + } + else + child_accessible = atk_object_ref_accessible_child (accessible, i); g_assert_cmpint (add_data.count, ==, i + 1); g_assert_cmpint (add_data.n_children, ==, step_children + i + 1); g_assert_cmpint (remove_data.count, ==, 0); - g_assert_cmpint (parent_data[i].count, ==, 1); + if (!GTK_IS_ENTRY (widget)) + g_assert_cmpint (parent_data[i].count, ==, 1); if (GTK_IS_SCROLLED_WINDOW (widget) || GTK_IS_NOTEBOOK (widget)) g_assert (atk_object_get_parent (ATK_OBJECT (parent_data[i].parent)) == accessible); + else if (GTK_IS_ENTRY (widget)) + g_assert (atk_object_get_parent (child_accessible) == accessible); else g_assert (parent_data[i].parent == accessible); + + if (GTK_IS_ENTRY (widget)) + g_object_unref (child_accessible); } for (j = 0 ; j < i; j++) { - remove_child (widget, child[j]); + remove_child (&state, j); g_assert_cmpint (add_data.count, ==, i); g_assert_cmpint (remove_data.count, ==, j + 1); g_assert_cmpint (remove_data.n_children, ==, step_children + i - j - 1); if (parent_data[j].count == 2) g_assert (parent_data[j].parent == NULL); - else + else if (!GTK_IS_ENTRY (widget)) { AtkStateSet *set; set = atk_object_ref_state_set (ATK_OBJECT (parent_data[j].parent)); @@ -205,6 +271,7 @@ main (int argc, char *argv[]) add_child_tests (gtk_statusbar_new ()); #endif add_child_tests (gtk_notebook_new ()); + add_child_tests (gtk_entry_new ()); return g_test_run (); } diff --git a/tests/a11y/entries.txt b/tests/a11y/entries.txt index cf15be17b6..8819516ee7 100644 --- a/tests/a11y/entries.txt +++ b/tests/a11y/entries.txt @@ -219,10 +219,66 @@ window1 action 0 name: activate action 0 keybinding: p + entry3 + "text" + parent: box1 + index: 5 + state: editable enabled focusable sensitive single-line visible + toolkit: gtk + + layer: widget + alpha: 1 + + text: icons + character count: 5 + caret offset: 0 + default attributes: bg-color: + bg-full-height: 0 + direction: + editable: false + family-name: + fg-color: + indent: 0 + invisible: false + justification: left + language: + left-margin: 0 + pixels-above-lines: 0 + pixels-below-lines: 0 + pixels-inside-wrap: 0 + right-margin: 0 + rise: 0 + scale: 1 + size: + stretch: + strikethrough: false + style: + underline: none + variant: + weight: + wrap-mode: word + + action 0 name: activate + unnamed-GtkEntryIconAccessible-0 + "icon" + state: enabled sensitive visible + + layer: widget + alpha: 1 + + action 0 name: activate + unnamed-GtkEntryIconAccessible-1 + "icon" + state: enabled sensitive visible + + layer: widget + alpha: 1 + + action 0 name: activate spinbutton1 "spin button" parent: box1 - index: 5 + index: 6 labelled-by: label3 state: editable enabled focusable horizontal sensitive single-line visible toolkit: gtk diff --git a/tests/a11y/entries.ui b/tests/a11y/entries.ui index 0243dd7a2d..280d3bc182 100644 --- a/tests/a11y/entries.ui +++ b/tests/a11y/entries.ui @@ -53,6 +53,14 @@ True + + + icons + True + stock1 + stock2 + + adjustment1 -- 2.30.2